package com.gitee.wsl.net.server.health

import io.ktor.http.HttpStatusCode
import io.ktor.server.routing.Route

/**
 * Configuration class used to configure [KHealthPlugin]. No values are required to be passed in as defaults
 * are provided.
 */
class KHealthConfiguration internal constructor() {
    internal var healthChecks = linkedSetOf<Check>()
    internal var readyChecks = linkedSetOf<Check>()
    internal var wrapWith: (Route.(next: Route.() -> Unit) -> Unit)? = null

    /**
     * The status code returned when a check fails. Defaults to 500 - Internal Server Error.
     */
    var unsuccessfulCheckStatusCode = HttpStatusCode.InternalServerError

    /**
     * The status code returned when all checks pass. Defaults to 200 - OK
     */
    var successfulCheckStatusCode = HttpStatusCode.OK

    /**
     * The path of the health check endpoint. Defaults to "/health".
     */
    var healthCheckPath = "/health"
        set(value) {
            field = normalizePath(value)
        }

    /**
     * The path of the ready check endpoint. Defaults to "/ready".
     */
    var readyCheckPath = "/ready"
        set(value) {
            field = normalizePath(value)
        }

    /**
     * Controls whether the health check endpoint is enabled or disabled. Defaults to true.
     */
    var healthCheckEnabled = true

    /**
     * Controls whether the ready check endpoint is enabled or disabled. Defaults to true.
     */
    var readyCheckEnabled = true

    /**
     * Builder function to add checks to the health endpoint.
     */
    fun healthChecks(init: CheckBuilder.() -> Unit) {
        healthChecks = CheckBuilder().apply(init).checks
    }

    /**
     * Builder function to add checks to the ready endpoint.
     */
    fun readyChecks(init: CheckBuilder.() -> Unit) {
        readyChecks = CheckBuilder().apply(init).checks
    }

    fun wrap(block: Route.(next: Route.() -> Unit) -> Unit) {
        wrapWith = block
    }


}

/**
 * Normalizes the provided URI and asserts that it's not blank.
 * The provided URI can have a slash, if it does not then one will be added to normalize it.
 * @param uri The provided URI
 */
private fun normalizePath(uri: String): String {
    return if (uri[0] == '/') {
        assertNotBlank(uri.removePrefix("/"))
        uri
    } else {
        assertNotBlank(uri)
        "/$uri"
    }
}

/**
 * Asserts the provided path value is not blank.
 */
private fun assertNotBlank(value: String) {
    require(value.isNotBlank()) {
        "The provided path must not be empty"
    }
}